home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Chat.c
- **
- ** Chat support code
- **
- ** Copyright © 1990-1996 by Olaf `Olsen' Barthel
- ** All Rights Reserved
- */
-
- #ifndef _GLOBAL_H
- #include "Global.h"
- #endif
-
- // Maximum number of characters to enter per line
-
- #define CHAT_LINE_SIZE 512
-
- // Local data
-
- STATIC struct List *ChatList;
- STATIC struct Node *ChatNode;
- STATIC STRPTR ChatBuffer,
- ChatUndo,
- ChatWork,
- ChatTemp;
- STATIC LONG ChatPosition;
- STATIC Object *ChatGadget;
- STATIC BOOLEAN ChatWasActive;
-
- /* ChatKey(REG(a1) ULONG *Msg,REG(a2) struct SGWork *Work):
- *
- * String gadget editing hook code. This is where all the
- * magic happens.
- */
-
- STATIC ULONG __saveds __asm
- ChatKey(REG(a1) ULONG *Msg,REG(a2) struct SGWork *Work)
- {
- /* Someone activated the string gadget and
- * hit a key.
- */
-
- if(*Msg == SGH_KEY)
- {
- BOOL NeedChange = FALSE,
- DidSomething = FALSE;
-
- // Remember that this gadget was activated
-
- Forbid();
-
- ChatWasActive = TRUE;
-
- Permit();
-
- // Clear the history list when pressing Amiga+Del/Amiga+Backspace
-
- if((Work -> IEvent -> ie_Qualifier & (AMIGARIGHT | AMIGALEFT)) && (Work -> IEvent -> ie_Code == DEL_CODE || Work -> IEvent -> ie_Code == BACKSPACE_CODE))
- {
- FreeList(ChatList);
-
- NewList(ChatList);
-
- ChatNode = NULL;
-
- Work -> Actions &= ~(SGA_USE | SGA_BEEP);
-
- return(TRUE);
- }
-
- /* Right-Amiga-key was pressed, release the
- * string gadget so user may select a menu
- * item.
- */
-
- if((Work -> IEvent -> ie_Qualifier & AMIGARIGHT) && Work -> IEvent -> ie_Code < 96)
- {
- if(!(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) && (Work -> IEvent -> ie_Code == KEYCODE_X || Work -> IEvent -> ie_Code == KEYCODE_Q))
- return(TRUE);
- else
- {
- Work -> Actions = (Work -> Actions & ~(SGA_USE | SGA_BEEP)) | SGA_END | SGA_REUSE;
-
- return(TRUE);
- }
- }
-
- // This looks like a function key. Send the corresponding macro.
-
- if(Work -> IEvent -> ie_Code >= F01_CODE && Work -> IEvent -> ie_Code <= F10_CODE)
- {
- STRPTR String;
- LONG Len,Index = Work -> IEvent -> ie_Code - F01_CODE;
-
- Forbid();
-
- // Pick the right macro
-
- if(Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL)
- String = MacroKeys -> Keys[3][Index];
- else
- {
- if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
- String = MacroKeys -> Keys[2][Index];
- else
- {
- if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
- String = MacroKeys -> Keys[1][Index];
- else
- String = MacroKeys -> Keys[0][Index];
- }
- }
-
- // Anything to send at all?
-
- if(Len = strlen(String))
- {
- struct DataMsg *Msg;
-
- if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 1))
- {
- Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
- Msg -> Data = (STRPTR)(Msg + 1);
-
- strcpy(Msg -> Data,String);
-
- // Send the command
-
- PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
- }
- }
-
- Permit();
-
- return(TRUE);
- }
-
- /* The user pressed the cursor-right key to
- * move the cursor to the next word in the buffer.
- */
-
- if(Work -> IEvent -> ie_Code == CURSORRIGHT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
- {
- if(Work -> BufferPos != Work -> NumChars)
- {
- LONG i,Position = -1;
-
- for(i = Work -> BufferPos ; i < Work -> NumChars ; i++)
- {
- if(Work -> WorkBuffer[i] == ' ')
- {
- for( ; i < Work -> NumChars ; i++)
- {
- if(Work -> WorkBuffer[i] != ' ')
- {
- Position = i;
- break;
- }
- }
-
- break;
- }
- }
-
- if(Position != -1)
- Work -> BufferPos = Position;
- else
- Work -> BufferPos = Work -> NumChars;
-
- Work -> EditOp = EO_MOVECURSOR;
- }
-
- return(TRUE);
- }
-
- /* The user pressed the cursor-right key to
- * move the cursor to the previous word in the buffer.
- */
-
- if(Work -> IEvent -> ie_Code == CURSORLEFT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
- {
- if(Work -> BufferPos)
- {
- LONG i,Position = -1;
-
- for(i = Work -> BufferPos ; i >= 0 ; i--)
- {
- if(Work -> WorkBuffer[i] != ' ')
- {
- Position = i;
- break;
- }
- }
-
- if(Position == -1)
- Position = 0;
-
- if(Position)
- {
- i = Position;
-
- Position = -1;
-
- for( ; i >= 0 ; i--)
- {
- if(Work -> WorkBuffer[i] == ' ')
- {
- Position = i + 1;
- break;
- }
- }
- }
-
- if(Position != -1)
- Work -> BufferPos = Position;
- else
- Work -> BufferPos = 0;
-
- Work -> EditOp = EO_MOVECURSOR;
- }
-
- DidSomething = TRUE;
- }
-
- /* The user pressed the cursor-up key to
- * scroll through the command history.
- */
-
- if(Work -> IEvent -> ie_Code == CURSORUP)
- {
- /* Shift key: jump to first command
- * history entry.
- */
-
- if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
- {
- if(ChatList -> lh_Head -> ln_Succ)
- ChatNode = ChatList -> lh_Head;
- else
- ChatNode = NULL;
-
- NeedChange = TRUE;
- }
- else
- {
- if(ChatNode)
- {
- if(ChatNode -> ln_Pred -> ln_Pred)
- {
- ChatNode = ChatNode -> ln_Pred;
-
- NeedChange = TRUE;
- }
- }
- else
- {
- if(ChatList -> lh_Head -> ln_Succ)
- {
- ChatNode = ChatList -> lh_TailPred;
-
- NeedChange = TRUE;
- }
- }
- }
-
- DidSomething = TRUE;
- }
-
- /* The user pressed the cursor-down key to
- * scroll through the command history.
- */
-
- if(Work -> IEvent -> ie_Code == CURSORDOWN)
- {
- /* Shift key: jump to last command
- * history entry.
- */
-
- if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
- {
- if(ChatList -> lh_Head -> ln_Succ)
- ChatNode = ChatList -> lh_TailPred;
- else
- ChatNode = NULL;
-
- NeedChange = TRUE;
- }
- else
- {
- if(ChatNode)
- {
- if(ChatNode -> ln_Succ -> ln_Succ)
- ChatNode = ChatNode -> ln_Succ;
- else
- ChatNode = NULL;
- }
-
- NeedChange = TRUE;
- }
-
- DidSomething = TRUE;
- }
-
- // Update the contents of the string gadget
-
- if(NeedChange)
- {
- LONG Len;
-
- if(ChatNode)
- strcpy(Work -> WorkBuffer,ChatNode -> ln_Name);
- else
- Work -> WorkBuffer[0] = 0;
-
- strcpy(Work -> StringInfo -> UndoBuffer,Work -> PrevBuffer);
-
- Work -> StringInfo -> UndoPos = Work -> BufferPos;
-
- Len = strlen(Work -> WorkBuffer);
-
- if(Len < Work -> BufferPos)
- Work -> BufferPos = Len;
-
- Work -> NumChars = Len;
- Work -> Actions = (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_REDISPLAY;
- }
-
- // User pressed return?
-
- if(Work -> Actions & SGA_END)
- {
- // Deactivate the gadget?
-
- if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
- {
- Work -> Actions &= ~SGA_END;
-
- Forbid();
-
- ChatWasActive = FALSE;
-
- Permit();
- }
- else
- {
- struct DataMsg *Msg;
- LONG Len = Work -> NumChars;
-
- // If any text was entered, add it to the history list
-
- if(Work -> WorkBuffer[0])
- {
- BOOL AddIt = TRUE;
-
- // Don't add duplicates
-
- if(ChatNode)
- {
- if(!Stricmp(ChatNode -> ln_Name,Work -> WorkBuffer))
- AddIt = FALSE;
- }
-
- // Allocate space for the text, then add it
-
- if(AddIt)
- {
- struct Node *SomeNode;
-
- if(SomeNode = (struct Node *)AllocVecPooled(sizeof(struct Node) + Len + 1,MEMF_ANY))
- {
- strcpy(SomeNode -> ln_Name = (STRPTR)(SomeNode + 1),Work -> WorkBuffer);
-
- AddTail(ChatList,SomeNode);
- }
- }
- }
-
- ChatNode = NULL;
-
- // Transfer the buffer
-
- if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 3))
- {
- STRPTR Extra;
-
- Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
- Msg -> Data = (STRPTR)(Msg + 1);
-
- strcpy(Msg -> Data,Work -> WorkBuffer);
-
- // Add EOL characters
-
- switch(Config -> TerminalConfig -> SendCR)
- {
- case EOL_CR:
-
- Extra = "\r";
- break;
-
- case EOL_LF:
-
- Extra = "\n";
- break;
-
- case EOL_CRLF:
-
- Extra = "\r\n";
- break;
-
- case EOL_LFCR:
-
- Extra = "\n\r";
- break;
-
- default:
-
- Extra = NULL;
- break;
- }
-
- if(Extra)
- strcpy(Msg -> Data + Len,Extra);
-
- // Clear the string gadget
-
- Work -> WorkBuffer[0] = 0;
- Work -> BufferPos = 0;
- Work -> NumChars = 0;
- Work -> Actions = (Work -> Actions & ~(SGA_BEEP | SGA_END)) | SGA_USE | SGA_REDISPLAY;
-
- Work -> StringInfo -> UndoPos = 0;
- Work -> StringInfo -> UndoBuffer[0] = 0;
-
- // Send the line
-
- PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
- }
- }
-
- DidSomething = TRUE;
- }
-
- // Control character entered?
-
- if(!DidSomething && Work -> Code && !(Work -> Code & 0xFFE0))
- {
- LONG Code = Work -> Code & 0x1F;
-
- if(Code == '\t' && Work -> IEvent -> ie_Code != TAB_CODE)
- return(TRUE);
-
- if(Code != '\r' && Code != '\b')
- {
- struct DataMsg *Msg;
-
- if(Code == ('S' & 0x1F) || Code == ('Q' & 0x1F))
- {
- if(Config -> SerialConfig -> xONxOFF)
- {
- Forbid();
-
- if(Code == ('S' & 0x1F))
- {
- if(Status == STATUS_READY)
- Status = STATUS_HOLDING;
- }
- else
- {
- if(Status == STATUS_HOLDING)
- Status = STATUS_READY;
- }
-
- Permit();
- }
-
- if(!Config -> SerialConfig -> PassThrough)
- return(TRUE);
- }
-
- if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + 2))
- {
- Work -> Actions &= ~SGA_USE;
-
- Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
- Msg -> Data = (STRPTR)(Msg + 1);
-
- Msg -> Data[0] = Code;
- Msg -> Data[1] = 0;
-
- PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
- }
- }
- }
-
- return(TRUE);
- }
- else
- {
- if(*Msg == SGH_CLICK)
- {
- // Remember activation
-
- Forbid();
-
- ChatWasActive = TRUE;
-
- Permit();
-
- return(TRUE);
- }
- else
- return(FALSE);
- }
- }
-
- /* HideChatGadget():
- *
- * Remove the chat gadget, but don't free the buffers.
- */
-
- VOID
- HideChatGadget()
- {
- if(ChatGadget)
- {
- GetAttr(STRINGA_BufferPos,ChatGadget,(ULONG *)&ChatPosition);
-
- RemoveGList(Window,(struct Gadget *)ChatGadget,1);
-
- DisposeObject(ChatGadget);
-
- ChatGadget = NULL;
- }
- }
-
- /* DeleteChatGadget():
- *
- * Remove the chat gadget, also take care of the buffers.
- */
-
- VOID
- DeleteChatGadget()
- {
- HideChatGadget();
-
- FreeVecPooled(ChatBuffer);
- ChatBuffer = NULL;
-
- DeleteList(ChatList);
- ChatList = NULL;
- }
-
- /* UpdateChatGadget():
- *
- * Redraw the chat gadget imagery.
- */
-
- VOID
- UpdateChatGadget()
- {
- if(ChatGadget)
- {
- struct RastPort *RPort = Window -> RPort;
- LONG Left,Right,Top;
-
- // Draw the separator bar
-
- if(StatusWindow || Config -> ScreenConfig -> StatusLine == STATUSLINE_DISABLED)
- Top = UserFontHeight;
- else
- Top = StatusDisplayHeight + UserFontHeight;
-
- Top = Window -> Height - (Window -> BorderBottom + Top + 2);
- Left = Window -> BorderLeft;
- Right = Window -> Width - (Window -> BorderRight + 1);
-
- SetAPen(RPort,Pens[SHADOWPEN]);
- Move(RPort,Left,Top);
- Draw(RPort,Right,Top);
-
- Top++;
-
- SetAPen(RPort,Pens[SHINEPEN]);
- Move(RPort,Left,Top);
- Draw(RPort,Right,Top);
-
- // Redraw the gadget
-
- RefreshGList((struct Gadget *)ChatGadget,Window,NULL,1);
- }
- }
-
- /* ActivateChat(BOOL Reactivate):
- *
- * Activate the chat gadget.
- */
-
- VOID
- ActivateChat(BOOL Reactivate)
- {
- if(ChatGadget)
- {
- Forbid();
-
- if(Reactivate)
- Reactivate = ChatWasActive;
- else
- Reactivate = TRUE;
-
- Permit();
-
- if(Reactivate)
- ActivateGadget((struct Gadget *)ChatGadget,Window,NULL);
- }
- }
-
- /* CreateChatGadget():
- *
- * Create the chat gadget and add it to the main window.
- */
-
- BOOL
- CreateChatGadget()
- {
- ChatWasActive = TRUE;
-
- // Allocate the history list
-
- if(!ChatList)
- {
- if(!(ChatList = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY)))
- return(FALSE);
- else
- NewList(ChatList);
-
- ChatNode = NULL;
- }
-
- // Allocate the undo/work/editing buffers
-
- if(!ChatBuffer)
- {
- if(!(ChatBuffer = (STRPTR)AllocVecPooled(5 * CHAT_LINE_SIZE,MEMF_ANY | MEMF_CLEAR)))
- {
- DeleteChatGadget();
-
- return(FALSE);
- }
- else
- {
- ChatUndo = ChatBuffer + CHAT_LINE_SIZE;
- ChatWork = ChatUndo + CHAT_LINE_SIZE;
- ChatTemp = ChatWork + CHAT_LINE_SIZE;
- }
- }
-
- // Finally create the gadget
-
- if(!ChatGadget)
- {
- STATIC struct Hook ChatHook = { {NULL},(HOOKFUNC)ChatKey };
-
- LONG Bottom = Window -> BorderBottom + UserFontHeight - 1;
-
- if(!StatusWindow && Config -> ScreenConfig -> StatusLine != STATUSLINE_DISABLED && !Config -> ScreenConfig -> SplitStatus)
- Bottom += StatusDisplayHeight;
-
- if(!(ChatGadget = NewObject(NULL,STRGCLASS,
- GA_Left, Window -> BorderLeft,
- GA_Height, UserFontHeight,
- GA_RelBottom, -Bottom,
- GA_RelWidth, -(Window -> BorderLeft + Window -> BorderRight),
- GA_TabCycle, FALSE,
- STRINGA_TextVal, ChatBuffer,
- STRINGA_MaxChars, CHAT_LINE_SIZE,
- STRINGA_Buffer, ChatBuffer,
- STRINGA_BufferPos, ChatPosition,
- STRINGA_UndoBuffer, ChatUndo,
- STRINGA_WorkBuffer, ChatWork,
- STRINGA_NoFilterMode, TRUE,
-
- // NOTE: This should really look like below,
- // according to the BOOPSI documentation.
- // Even worse, the pen numbers are in reality
- // truncated to a maximum of colour # 15.
-
- // STRINGA_Pens, ((LONG)Pens[BACKGROUNDPEN] << 16) | Pens[TEXTPEN],
- // STRINGA_ActivePens, ((LONG)Pens[BACKGROUNDPEN] << 16) | Pens[TEXTPEN],
-
- STRINGA_Pens, (Pens[BACKGROUNDPEN] << 8) | Pens[TEXTPEN],
- STRINGA_ActivePens, (Pens[BACKGROUNDPEN] << 8) | Pens[TEXTPEN],
- STRINGA_EditHook, &ChatHook,
- TAG_DONE)))
- {
- DeleteChatGadget();
-
- return(FALSE);
- }
- else
- AddGList(Window,(struct Gadget *)ChatGadget,(UWORD)~0,1,NULL);
- }
-
- return(TRUE);
- }
-